package cn.com.bluemoon.daps.standard.service.impl;

import cn.com.bluemoon.daps.api.sys.RemoteSystemDatasourceService;
import cn.com.bluemoon.daps.common.constant.DapConstant;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.model.entity.DapDataModel;
import cn.com.bluemoon.daps.model.entity.DapDataModelTable;
import cn.com.bluemoon.daps.model.entity.DapDataModelTableField;
import cn.com.bluemoon.daps.standard.common.report.AbstractReportCheck;
import cn.com.bluemoon.daps.model.dto.ModelDto;
import cn.com.bluemoon.daps.model.dto.ModelTableDto;
import cn.com.bluemoon.daps.standard.entity.*;
import cn.com.bluemoon.daps.system.entity.DapSystemDatasource;
import cn.com.bluemoon.daps.common.enums.DatabaseType;
import cn.com.bluemoon.daps.common.enums.StandardDataType;
import cn.com.bluemoon.daps.standard.service.*;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 生成标准报告
 *
 * @author Jarod.Kong
 * @date 2020/9/25 16:43
 */
@Component(DapConstant.AUDIT_SYSTEM_REPORT_STANDARD)
public class ModelStandardReportCheckImpl extends AbstractReportCheck<DapAuditStandardResult> {

    @Resource
    private DapStandardBasicService standardBasicService;

    @Resource
    private DapStandardDataTypeService standardDataTypeService;

    @Resource
    private DapAuditFieldStandardResultService fieldStandardResultService;

    @Resource
    private DapAuditStandardResultService standardResultService;

    /**
     * @param modelDto
     * @return 报告实现函数
     */
    @Override
    public Function<ModelTableDto, DapAuditStandardResult> reportCheckFunc(ModelDto modelDto) {
        DapDataModel model = modelDto.getModel();
        String sysAuditResultId = modelDto.getSysAuditCheckResultId();
        return tableModelDto -> {
            final String standardResultId = IdWorker.getIdStr();
            DapDataModelTable table = tableModelDto.getTable();
            List<DapDataModelTableField> fields = tableModelDto.getFields();
            List<DapAuditFieldStandardResult> fieldStandardResults = getFieldStandardResults(modelDto, standardResultId, fields);
            if (!fieldStandardResults.isEmpty()) {
                fieldStandardResultService.saveBatch(fieldStandardResults);
            }
            long markRelateStandardSize = fieldStandardResults.stream().filter(d -> d.getIsMapping() == 1).count();
            long passCount = fieldStandardResults.stream().filter(d -> d.getIsPassed() == 1).count();
            DapAuditStandardResult result = new DapAuditStandardResult();
            result.setId(standardResultId);
            int fieldSize = fields.size();
            result.setFieldCoincidenceRate(formatPercent(Math.toIntExact(passCount), fieldSize));
            result.setFieldTotal(String.valueOf(fieldSize));
            result.setModelId(model.getId());
            result.setModelName(model.getName());
            result.setTableChinName(table.getName());
            result.setTableId(table.getId());
            result.setTableName(table.getEngName());
            result.setNumStandardsAdopted(String.valueOf(markRelateStandardSize));
            result.setIsPassed((passCount == fieldSize) ? 1 : 0);
            result.setSystemAuditResultId(sysAuditResultId);
            standardResultService.save(result);
            return result;
        };
    }

    /**
     * @param model
     * @param standardResultId
     * @param fields
     * @return
     */
    private List<DapAuditFieldStandardResult> getFieldStandardResults(ModelDto model,
                                                                      String standardResultId,
                                                                      List<DapDataModelTableField> fields) {
        DatabaseType databaseType = model.getDatabaseType();
        Map<Integer, Set<String>> codeTypeAndDataTypes = standardDataTypeService.getMapDataTypeByDbType(databaseType);
        // 缓存获取全基础标准数据（与产品确认基础标准最多在几千条，直接缓存）
        Map<String, DapStandardBasic> allPublish = standardBasicService.findAllPublishGroupByStandardUniqueId();
        return fields.parallelStream().map(field -> {
            DapAuditFieldStandardResult fieldStd = new DapAuditFieldStandardResult();
            fieldStd.setFieldName(field.getFieldName());
            fieldStd.setFieldChinName(field.getComment());
            fieldStd.setFieldLong(field.getLength());
            fieldStd.setFieldType(field.getDataType());
            fieldStd.setFieldNewestId(field.getPId());
            fieldStd.setFieldId(field.getId());
            fieldStd.setIsMapping(0);
            // 乐观默认为通过
            fieldStd.setIsPassed(1);
            fieldStd.setStandardResultId(standardResultId);
            // 标准存在且不为空
            String standardId = field.getStandardId();
            DapStandardBasic standardBasic = null;
            if ((standardBasic = allPublish.get(standardId)) != null) {
                fieldStd.setIsMapping(1);
                // 标准名称
                fieldStd.setStandardsAdopted(standardBasic.getName());
                fieldStd.setStandardsLong(standardBasic.getDataLength());
                fieldStd.setStandardsType(standardBasic.getDataType().name());
                fieldStd.setStandardUniqueId(standardBasic.getStandardUniqueId());
                Integer standardMethod = field.getStandardMethod();
                String relStandardMethod = standardMethod != null && standardMethod == 2 ? "自动匹配" : "手动关联";
                fieldStd.setRelStandardMethod(relStandardMethod);
                List<String> resons = Lists.newArrayList();
                if (!isEqualsByTrimAndToEmpty(standardBasic.getDataLength(), field.getLength())) {
                    resons.add("数据长度不一致");
                }
                /**
                 * {@link DapStandardBasic#getDataType()} 对应的{@link StandardDataType#getCode()}  + {@link DapStandardDataType#getCodeType()} ()} 获取相关字段类型，
                 * 判断{@link DapDataModelTableField#getDataType()} 是否在其中
                 * 初始化{@link DapStandardBasic#getDataType()}对应的{@link StandardDataType#getCode()}  + {@link DapStandardDataType#getDbType()}的关系数据
                 */
                Set<String> stdDataTypes = null;
                if (standardBasic.getDataType() != null && (stdDataTypes = codeTypeAndDataTypes.get(standardBasic.getDataType().getCode())) != null) {
                    if (!stdDataTypes.contains(field.getDataType())) {
                        resons.add("数据类型不一致");
                    }
                } else {
                    resons.add("数据类型不一致");
                }
                if (!resons.isEmpty()) {
                    fieldStd.setReason(String.join(";", resons));
                    fieldStd.setIsPassed(0);
                }
            }
            return fieldStd;
        }).collect(Collectors.toList());
    }


    /**
     * 基于结果定义是否未通过
     *
     * @param list
     * @return
     */
    @Override
    public boolean checkPass(List<DapAuditStandardResult> list) {
        return list.stream().allMatch(d -> d.getIsPassed() == 1);
    }
}
